/*
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package au.com.domlogic.pvc.xhtml.component.builder;

import au.com.domlogic.pvc.core.component.ComponentMold;
import au.com.domlogic.pvc.core.component.ComponentMoldBuilder;
import au.com.domlogic.pvc.core.element.ElementMold;
import au.com.domlogic.pvc.xhtml.attr.ClassAttrMold;
import au.com.domlogic.pvc.xhtml.element.LiElementMold;
import au.com.domlogic.pvc.xhtml.element.PElementMold;
import au.com.domlogic.pvc.xhtml.element.UlElementMold;
import java.util.ArrayList;
import java.util.List;

/**
 * This builder builds the Mold for a tree representation of a ComponentMold.
 * This is useful for viewing the and editing the structure of a ComponentMold.
 * @author Domenic Figliomeni
 */
public class ComponentTreeMoldBuilder implements ComponentMoldBuilder {

    private static final String TREE_ROOT_CSS_CLASS_DEFAULT = "componentMoldTreeRoot";
    private static final String TREE_BRANCH_CSS_CLASS_DEFAULT = "componentMoldTreeBranch";
    private ComponentMold componentMold;
    private String treeRootCssClass;
    private String treeBranchCssClass;

    public ComponentTreeMoldBuilder() {
        this.treeRootCssClass = TREE_ROOT_CSS_CLASS_DEFAULT;
        this.treeBranchCssClass = TREE_BRANCH_CSS_CLASS_DEFAULT;
    }

    @Override
    public UlElementMold buildComponentMold() {
        UlElementMold Mold = new UlElementMold();
        if (treeRootCssClass != null && !treeRootCssClass.equals("")) {
            //Set a class for css to hook in
            Mold.addAttrMold(new ClassAttrMold(treeRootCssClass));
        }
        if (componentMold != null) {
            List<ComponentMold> base = new ArrayList<ComponentMold>();
            base.add(componentMold);
            buildTree(Mold, base);
        }
        return Mold;
    }

    private void buildTree(UlElementMold parentUl, List<ComponentMold> parents) {
        if (treeBranchCssClass != null && !treeBranchCssClass.equals("")) {
            //Set a class for css to hook in
            parentUl.addAttrMold(new ClassAttrMold(treeBranchCssClass));
        }
        for (ComponentMold parent : parents) {
            LiElementMold li = new LiElementMold();
            parentUl.addComponentMold(li);
            //Pre Children View
            ComponentMold preChildrenView;
            if (parent instanceof ElementMold) {
                ElementMold elementMold = (ElementMold) parent;
                preChildrenView = produceElementMoldPreChildrenView(elementMold);
                if (preChildrenView != null) {
                    li.addComponentMold(produceElementMoldPreChildrenView(elementMold));
                }
            } else {
                preChildrenView = produceComponentMoldPreChildrenView(parent);
                if (preChildrenView != null) {
                    li.addComponentMold(produceComponentMoldPreChildrenView(parent));
                }
            }
            //Children
            List<ComponentMold> children = parent.getComponentMolds();
            if (children != null && !children.isEmpty()) {
                UlElementMold childrenUl = new UlElementMold();
                li.addComponentMold(childrenUl);
                buildTree(childrenUl, children);
            }
            //Post Children View
            ComponentMold postChildrenView;
            if (parent instanceof ElementMold) {
                ElementMold elementMold = (ElementMold) parent;
                postChildrenView = produceElementMoldPostChildrenView(elementMold);
                if (postChildrenView != null) {
                    li.addComponentMold(postChildrenView);
                }
            } else {
                postChildrenView = produceComponentMoldPostChildrenView(parent);
                if (postChildrenView != null) {
                    li.addComponentMold(postChildrenView);
                }
            }
        }
    }

    /**
     * Produces a paragraph element Mold to append to the tree branch li.
     * Override this to make your own rules about what to append.
     * @param Mold
     * @return The Component Mold to append to the tree branch li when an Element
     * Mold is encountered.
     */
    protected ComponentMold produceElementMoldPreChildrenView(ElementMold elementMold) {
        String elementLabel = elementMold.getTagName();
        PElementMold p = new PElementMold();
        p.setContent("<" + elementLabel + ">");
        return p;
    }

    /**
     * Does not produce a Mold for the view of a ComponentMold child.  Override
     * this if you wish to add some markup to show that there is a component Mold
     * present.
     * @param Mold
     * @return null
     */
    protected ComponentMold produceComponentMoldPreChildrenView(ComponentMold componentMold) {
        return null;
    }

    /**
     * Produces a paragraph element Mold to append to the tree branch li.
     * Override this to make your own rules about what to append.
     * @param Mold
     * @return The Component Mold to append to the tree branch li when an Element
     * Mold is encountered.
     */
    protected ComponentMold produceElementMoldPostChildrenView(ElementMold elementMold) {
        String elementLabel = elementMold.getTagName();
        PElementMold p = new PElementMold();
        p.setContent("</" + elementLabel + ">");
        return p;
    }

    /**
     * Does not produce a Mold for the view of a ComponentMold child.  Override
     * this if you wish to add some markup to show that there is a component Mold
     * present.
     * @param Mold
     * @return null
     */
    protected ComponentMold produceComponentMoldPostChildrenView(ComponentMold componentMold) {
        return null;
    }

    public ComponentMold getComponentMold() {
        return componentMold;
    }

    public void setComponentMold(ComponentMold componentMold) {
        this.componentMold = componentMold;
    }

    public String getTreeBranchCssClass() {
        return treeBranchCssClass;
    }

    public void setTreeBranchCssClass(String treeBranchCssClass) {
        this.treeBranchCssClass = treeBranchCssClass;
    }

    public String getTreeRootCssClass() {
        return treeRootCssClass;
    }

    public void setTreeRootCssClass(String treeRootCssClass) {
        this.treeRootCssClass = treeRootCssClass;
    }
}
